/**
 * This software was produced for the U. S. Government
 * under Contract No. FA8721-09-C-0002, and is
 * subject to the Rights in Noncommercial Computer Software
 * and Noncommercial Computer Software Documentation Clause
 * (DFARS) 252.227-7014 (JUN 1995)
 * 
 * (c) 2009 The MITRE Corporation. All Rights Reserved.
 *
 * SPMIF to OPNET Translator
 * Author: EWALTERS
 * Created: 2:34:18 PM, Nov 2, 2007
 * MITRE Corporation
 */
package com.mitre.spmif2opnet.analysis;

import java.util.*;

import com.mitre.spmif2opnet.analysis.ast.Scenario;

/**
 * This abstract class is the (abstract) super class for calculating
 *  priorities using various means.
 * We collect the S-PMIF priorities, keyed by project and scenario names, 
 *  manually trigger the priority calculation, and expose the OPNET
 *  priorities once the calculation is done.  Manual triggering of the 
 *  calculation is necessary because we don't know a priori how many
 *  scenarios we may encounter, but for some of our calculations
 *  we need a complete set!
 */
public abstract class Priorities {
	/**
	 * Upper limit of the S-PMIF priority scales
	 */
	protected double _spmif_scale = 16.0;
	/**
	 * Upper limit of the OPNET priority scale
	 */
	protected double _opnet_scale = 10.0;
	/**
	 * Node identifier (as string) to SPMIF priority map
	 */
	protected Map<String, Integer> _spmif_priorities;
	/**
	 * Node identifier (as string) to OPNET priority map
	 */
	protected Map<String, Integer> _opnet_priorities;
	/**
	 * Have we run processing?
	 */
	protected boolean _processed;
	/**
	 * What kinds of priorities are we processing?
	 */
	protected PriorityType _type;
	
	/**
	 * Cnstructor
	 * @param type types of priorities
	 */
	public Priorities(PriorityType type) {
		_spmif_priorities = new Hashtable<String, Integer>();
		_opnet_priorities = new Hashtable<String, Integer>();
		_processed = false;
		_type = type;
	}
	
	/**
	 * Adds an S-PMIF priority to the priority list
	 * @param proj_name Project containing the priority
	 * @param scen_name Scenario (thread) to which the priority is assigned - 
	 *  we include the entire scenario because we may need info besides just
	 *  priority, e.g. for RMA scheduling
	 */
	public void addSpmifPriority(String proj_name, Scenario scen) {
		Identifier id = new Identifier();
		id.setProjectName(proj_name);
		id.setScenarioName(scen.getName());
		_spmif_priorities.put(id.toString(), scen.getPriority());
	}
	
	/**
	 * Gives the processed priority for insertion into OPNET when we convert from S-PMIF
	 *  scenarios to OPNET jobs.  -1 indicates priority processing has yet to occur
	 * @param proj_name Project containing the priority
	 * @param scen_name Scenario (thread) to which the priority is assigned
	 * @return calculated priority value, -1 if not calculated
	 */
	public int getOpnetPriority(String proj_name, String scen_name) {
		if (!_processed) return -1;
		Identifier id = new Identifier();
		id.setProjectName(proj_name);
		id.setScenarioName(scen_name);
		Integer p = _opnet_priorities.get(id.toString());
		if (p == null) { return -1; } else { return p; } 
	}
	
	/**
	 * Return the priority type
	 * @return the type
	 */
	public PriorityType getPriorityType() {
		return _type;
	}
	
	/**
	 * Abstract function implemented by each subclass - this is what will differ
	 * @throws AnalysisException
	 */
	public abstract void calculate() throws AnalysisException;

	/**
	 * The priority enumeration 
	 * - each has a makePriorities function that returns the corresponding priority
	 *   calculator
	 * - each also has a validString parser that parses the command-line
	 *   argument string to determine which priority calculation to implement 
	 * @author EWALTERS
	 */
	public enum PriorityType {
		RMA_PRIORITY { 
			public Priorities makePriorities() {
				return new RMAPriorities(this);
			}
			public boolean validString(String s) {
				return s.equals("RM");
			}
		},
		DIRECT_PRIORITY { 
			public Priorities makePriorities() {
				return new DirectPriorities(this);
			}
			public boolean validString(String s) {
				return s.equals("DIRECT");
			}
		},
		SCALED_PRIORITY { 
			public Priorities makePriorities() {
				return new ScaledPriorities(this);
			}
			public boolean validString(String s) {
				return s.equals("SCALED");
			}
		},
		ORDERED_PRIORITY {
			public Priorities makePriorities() {
				return new OrderedPriorities(this);
			}
			public boolean validString(String s) {
				return s.equals("ORDERED");
			}
		},
		NO_PRIORITY {
			public Priorities makePriorities() {
				return null;
			}
			public boolean validString(String s) {
				return false;
			}
		};
		
		public    abstract Priorities makePriorities();
		protected abstract boolean validString(String s);
		/** 
		 * Static function to parse priorities from an input string
		 * @param s the input string
		 * @return the enumeration, which can the be used to make the
		 *   priority calculator
		 */
		public static PriorityType fromString(String s) {
			for (PriorityType ptype : PriorityType.values()) {
				if (ptype.validString(s)) {
					return ptype;
				}
			}
			return null;
		}
	}

}
